package de.playmee.handler;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import de.playmee.XMLParser;
import de.playmee.enums.Result;
import android.content.SharedPreferences;
import android.util.Log;

public class AccountHandler {
	
	private final String TAG = "AccountHandler";
	
	// preferences
	public final static String PREFERENCES = "AccountPrefs";
	private final String PREFS_USERNAME = "username";
	private final String PREFS_PASSWORD = "password";
	private SharedPreferences preferences;
	
	// account attributes
	private String username;
	private String password;
	
	
	public AccountHandler(SharedPreferences preferences) {
		this.preferences = preferences;
	}
	
	/**
	 * sets and stores the username
	 * 
	 * @param user
	 */
	public void setUsername(String username) {
		this.username = username;
		SharedPreferences.Editor editor = preferences.edit();
		editor.putString(PREFS_USERNAME, username);
		editor.commit();
		Log.i(TAG, "Username stored.");
	}
	
	/**
	 * sets and stores the password
	 * 
	 * @param password
	 */
	public void setPassword(String password) {
		this.password = password;
		SharedPreferences.Editor editor = preferences.edit();
		editor.putString(PREFS_PASSWORD, password);
		editor.commit();
		Log.i(TAG, "Password stored.");
	}
	
	/**
	 * @return username
	 */
	public String getUsername() {
		return username;
	}
	
	/**
	 * @return password
	 */
	public String getPassword() {
		return password;
	}
	
	/**
	 * @return true if username and password are available, false otherwise
	 */
	public boolean accountDetailsAvailable() {
		return !username.isEmpty() && !password.isEmpty();
	}
	
	/**
	 * loads the stored username from preferences
	 */
	public void loadUsernameFromPreferences() {
		Log.i(TAG, "Load username from preferences...");
		username = preferences.getString(PREFS_USERNAME, "");
	}
	
	/**
	 * loads the stored password from preferences
	 */
	public void loadPasswordFromPreferences() {
		Log.i(TAG, "Load password from preferences...");
		password = preferences.getString(PREFS_PASSWORD, "");
	}
	
	/**
	 * checks if username and password are correct
	 * 
	 * @param username
	 * @param password
	 * @return Result
	 */
	public Result checkAccount(String username, String password) {
		Log.i(TAG, "Sending username and password to the database...");	
		Result result = Result.Success;
		
		String spec = "http://aj-nk.de/mrs/v2/main.php?method=login&user="
				+ username + "&pw=" + getMD5Hash(password);
		Log.i(TAG, spec);
		
		Document doc = null;
		try {
			doc = XMLParser.getDocument(spec);
		} catch(Exception e) {
			Log.i(TAG, "Error while sending account details.");
			result = Result.ParsingException;
		}
		
		if (result == Result.Success) {
			NodeList results = doc.getElementsByTagName("SUCCESS");
			if (results.getLength() == 0) {
				// error
				results = doc.getElementsByTagName("error");
				if (results.getLength() > 0) {
					// only use error 'wrong password', otherwise user gets too much information
					// and could first guess the username and then guess the password
					result = Result.Wrong_Password;
				} else {
					result = Result.ParsingException;
				}
			}
		}
		
		Log.i(TAG, "Finished checking the user account.");
		return result;
	}
	
	/**
	 * registers a new account (if possible)
	 * 
	 * @param username
	 * @param password
	 * @return
	 */
	public Result registerAccount(String username, String password) {
		Log.i(TAG, "Sending username and password to the database...");
		String spec = "http://aj-nk.de/mrs/v2/main.php?method=register&user="
				+ username + "&pw=" + getMD5Hash(password);
		Log.i(TAG, spec);
		
		Document doc;
		try {
			doc = XMLParser.getDocument(spec);
		} catch(Exception e) {
			Log.i(TAG, "Error while sending account details.");
			e.printStackTrace();
			return Result.ParsingException;
		}
		
		NodeList results = doc.getElementsByTagName("SUCCESS");
		if (results.getLength() == 0) {
			// error
			results = doc.getElementsByTagName("error");
			if (results.getLength() > 0) {
				// username already exists (error code 18)
				return Result.Duplicate_Username;
			} else {
				// unknown error code
				return Result.ParsingException;
			}
		}
		return Result.Success;
	}
	
	/**
	 * computes a md5 hash of the given string
	 * 
	 * @param input
	 * @return md5 hash
	 */
	private String getMD5Hash(String input) {
		byte[] defaultBytes = input.getBytes();
		try {
			MessageDigest algorithm = MessageDigest.getInstance("MD5");
			algorithm.reset();
			algorithm.update(defaultBytes);
			byte messageDigest[] = algorithm.digest();
			return toHexString(messageDigest);
		} catch(NoSuchAlgorithmException nsae){
			nsae.printStackTrace();
		}
		return null;
	}
	
	/**
	 * converts bytes into a hexadecimal string
	 * 
	 * @param bytes
	 * @return
	 */
	private String toHexString(byte[] bytes) { 
		char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; 
	    char[] hexChars = new char[bytes.length * 2]; 
	    int v; 
	    for ( int j = 0; j < bytes.length; j++ ) { 
	        v = bytes[j] & 0xFF; 
	        hexChars[j*2] = hexArray[v/16]; 
	        hexChars[j*2 + 1] = hexArray[v%16]; 
	    } 
	    return new String(hexChars); 
	} 
}
